#include "Time.h"

bool NahidaProject::Time::IsValid(int h, int m, int s) const {
	return (h >= 0 && h <= 23) && (m >= 0 && m <= 59) && (s >= 0 && s <= 59);
}

void NahidaProject::Time::Normalize() {
	int totalSeconds = hour * 3600 + minute * 60 + second;

	if (totalSeconds < 0) {
		totalSeconds += 86400;
	}

	totalSeconds %= 86400;
	if (totalSeconds < 0) {
		totalSeconds += 86400;
	}

	hour = totalSeconds / 3600;
	minute = (totalSeconds % 3600) / 60;
	second = totalSeconds % 60;
}

NahidaProject::Time& NahidaProject::Time::operator=(const Time& other) {
	if (this != &other) {
		hour = other.hour;
		minute = other.minute;
		second = other.second;
	}
	return *this;
}

int NahidaProject::Time::GetHour() const {
	return hour;
}

int NahidaProject::Time::GetMinute() const {
	return minute;
}

int NahidaProject::Time::GetSecond() const {
	return second;
}

void NahidaProject::Time::SetHour(int h) {
	if (h < 0 || h > 23) {
		throw std::invalid_argument("Hour must be between 0 and 23");
	}
	hour = h;
}

void NahidaProject::Time::SetMinute(int m) {
	if (m < 0 || m > 59) {
		throw std::invalid_argument("Minute must be between 0 and 59");
	}
	minute = m;
}

void NahidaProject::Time::SetSecond(int s) {
	if (s < 0 || s > 59) {
		throw std::invalid_argument("Second must be between 0 and 59");
	}
	second = s;
}

void NahidaProject::Time::SetTime(int h, int m, int s) {
	if (!IsValid(h, m, s)) {
		throw std::invalid_argument("Invalid time values");
	}
	hour = h;
	minute = m;
	second = s;
}

int NahidaProject::Time::ToSeconds() const {
	return hour * 3600 + minute * 60 + second;
}

void NahidaProject::Time::AddHours(int hours) {
	hour += hours;
	Normalize();
}

void NahidaProject::Time::AddMinutes(int minutes) {
	minute += minutes;
	Normalize();
}

void NahidaProject::Time::AddSeconds(int seconds) {
	second += seconds;
	Normalize();
}

void NahidaProject::Time::AddTime(int h, int m, int s) {
	hour += h;
	minute += m;
	second += s;
	Normalize();
}

void NahidaProject::Time::SubtractHours(int hours) {
	hour -= hours;
	Normalize();
}

void NahidaProject::Time::SubtractMinutes(int minutes) {
	minute -= minutes;
	Normalize();
}

void NahidaProject::Time::SubtractSeconds(int seconds) {
	second -= seconds;
	Normalize();
}

void NahidaProject::Time::SubtractTime(int h, int m, int s) {
	hour -= h;
	minute -= m;
	second -= s;
	Normalize();
}

int NahidaProject::Time::Difference(const Time& other) const {
	return this->ToSeconds() - other.ToSeconds();
}

std::string NahidaProject::Time::ToString() const {
	std::ostringstream oss;
	oss << std::setfill('0') << std::setw(2) << hour << ":" << std::setfill('0') << std::setw(2) << minute << ":" << std::setfill('0') << std::setw(2) << second;
	return oss.str();
}

std::string NahidaProject::Time::To12HourFormat() const {
	std::ostringstream oss;
	int displayHour = hour % 12;
	if (displayHour == 0) {
		displayHour = 12;
	}
	std::string period = (hour < 12) ? "AM" : "PM";

	oss << std::setfill('0') << std::setw(2) << displayHour << ":" << std::setfill('0') << std::setw(2) << minute << ":" << std::setfill('0') << std::setw(2) << second << " " << period;
	return oss.str();
}

NahidaProject::Time NahidaProject::Time::operator+(const Time& other) const {
	Time result(*this);
	result.AddTime(other.hour, other.minute, other.second);
	return result;
}

NahidaProject::Time NahidaProject::Time::operator-(const Time& other) const {
	Time result(*this);
	result.SubtractTime(other.hour, other.minute, other.second);
	return result;
}

NahidaProject::Time& NahidaProject::Time::operator+=(const Time& other) {
	AddTime(other.hour, other.minute, other.second);
	return *this;
}

NahidaProject::Time& NahidaProject::Time::operator-=(const Time& other) {
	SubtractTime(other.hour, other.minute, other.second);
	return *this;
}

bool NahidaProject::Time::operator==(const Time& other) const {
	return hour == other.hour && minute == other.minute && second == other.second;
}

bool NahidaProject::Time::operator!=(const Time& other) const {
	return !(*this == other);
}

bool NahidaProject::Time::operator<(const Time& other) const {
	return this->ToSeconds() < other.ToSeconds();
}

bool NahidaProject::Time::operator<=(const Time& other) const {
	return (*this < other) || (*this == other);
}

bool NahidaProject::Time::operator>(const Time& other) const {
	return !(*this <= other);
}

bool NahidaProject::Time::operator>=(const Time& other) const {
	return !(*this < other);
}

NahidaProject::Time& NahidaProject::Time::operator++() {
	AddSeconds(1);
	return *this;
}

NahidaProject::Time& NahidaProject::Time::operator--() {
	SubtractSeconds(1);
	return *this;
}

NahidaProject::Time NahidaProject::Time::operator++(int) {
	Time temp(*this);
	AddSeconds(1);
	return temp;
}

NahidaProject::Time NahidaProject::Time::operator--(int) {
	Time temp(*this);
	SubtractSeconds(1);
	return temp;
}

NahidaProject::Time NahidaProject::Time::Parse(const std::string& timeStr) {
	if (timeStr.length() != 8) {
		throw std::invalid_argument("Invalid time format");
	}

	int h = std::stoi(timeStr.substr(0, 2));
	int m = std::stoi(timeStr.substr(3, 2));
	int s = std::stoi(timeStr.substr(6, 2));

	return Time(h, m, s);
}

NahidaProject::Time NahidaProject::Time::Now() {
	return Time(12, 30, 45);
}
